import pickle
from typing import Annotated

from fastapi import APIRouter, Header, Depends

from app_v2.AsyncDataBase import get_async_db_cursor
from app_v2.bili_api.api import ApiSession
from app_v2.bili_api.bvid import Bvid
from app_v2.dependencys import get_redis
from app_v2.model import fmt, TrendingPageParams

video = APIRouter(prefix="/video", tags=["video"])


@video.get("/recommend")
async def recommend():
    return {
        "code": 200,
        "data": await Bvid.video_recommended()
    }


@video.get("/hot")
async def hot_video(tid: int = 0, update=False, redis=Depends(get_redis)):
    if not update:
        data = await redis.get("video:hot:{}".format(tid))
        if data:
            return {"code": 200, "data": pickle.loads(data)}

    info = await Bvid.get_rank_video(tid)
    res = list(map(lambda video: video.to_dict(), info))
    await redis.setex("video:hot:{}".format(tid), 3600, pickle.dumps(res))
    return {
        "code": 200,
        "data": res
    }


@video.get("/hot/my")
async def hot_video(ps: int = 20, pn: int = 1, token: Annotated[str | None, Header()] = None):
    return {
        "code": 200,
        "data": await Bvid.popular(ps, pn, token)
    }


@video.get("/series")
async def series(token: Annotated[str | None, Header()] = None, update=False, redis=Depends(get_redis)):
    if not update:
        data = await redis.get("video:series")
        if data:
            return {"code": 200, "data": pickle.loads(data)}

    res = await Bvid.lastest_series(token)
    await redis.setex("video:series", 3600, pickle.dumps(res))
    return {
        "code": 200,
        "data": res
    }


@video.get("/basic_info")
async def video_basic_info(bvid: str, update=False, redis=Depends(get_redis)):
    if not update:
        data = await redis.get("video:basic_info:{}".format(bvid))
        if data:
            return {"code": 200, "data": pickle.loads(data)}
    async with ApiSession(bvid) as session:
        info = await session.video(bvid).info()
    await redis.setex("video:basic_info:{}".format(bvid), 3600, pickle.dumps(info.to_dict()))
    return {
        "code": 200,
        "data": info.to_dict()
    }


@video.get("/ai_desc")
async def ai_desc(bvid: str, token: Annotated[str | None, Header()]):
    async with ApiSession(token) as session:
        desc = await session.video(bvid).ai_desc()
    return {
        "code": 200,
        "data": desc
    }


async def _db_change_field(bvid, field, params: TrendingPageParams, cursor):
    if field not in ["view_count", "coin_count", "share_count", "favorite_count"]:
        return {
            "code": 500,
            "message": "internal error"
        }

    sql = f"""
          SELECT MAX({field}) as {field}, DATE_FORMAT(date, %s) as date
          FROM video_info
          WHERE bvid = %s
          GROUP BY DATE_FORMAT(date, %s)
          ORDER BY DATE_FORMAT(date, %s) DESC
          LIMIT %s
          OFFSET %s
          """

    await cursor.execute(sql, [fmt[params.mode.value], bvid, fmt[params.mode.value], fmt[params.mode.value],
                               params.ps,
                               params.ps * params.pn])
    return {
        "code": 200,
        "data": await cursor.fetchall()
    }


@video.get("/change/views")
async def video_views_change(bvid: str, params: TrendingPageParams = Depends(), cursor=Depends(get_async_db_cursor)):
    return await _db_change_field(bvid, "view_count", params, cursor)


@video.get("/change/coins")
async def video_coins_change(bvid: str, params: TrendingPageParams = Depends(), cursor=Depends(get_async_db_cursor)):
    return await _db_change_field(bvid, "coin_count", params, cursor)


@video.get("/change/share")
async def video_share_change(bvid: str, params: TrendingPageParams = Depends(), cursor=Depends(get_async_db_cursor)):
    return await _db_change_field(bvid, "share_count", params, cursor)


@video.get("/change/favorite")
async def video_favorite_change(bvid: str, params: TrendingPageParams = Depends(), cursor=Depends(get_async_db_cursor)):
    return await _db_change_field(bvid, "favorite_count", params, cursor)
